// Copyright  2004-2008 Backplane Ltd.
//
// This file is part of Ubiquity formsPlayer
//
// Ubiquity formsPlayer is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3 of the License, or (at your
// option) any later version.
//
// Ubiquity formsPlayer is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License
// along with Ubiquity formsPlayer If not, see <http://www.gnu.org/licenses/>.
//	
//
//   Purpose:  Implementation of CXFormsDebugAgent.
//   $Id$


#include "stdafx.h"
#include "XFormsDebugAgent.h"
#include "XFormsApp.h"
#include <new>
#include "eventmsg.h"
#include "FP_Definitions.h"
#include "Model.h"
#include "implInstance.h"
#include "mapBSTRToInstancePtr.h"

extern CXFormsApp theApp;

CXFormsDebugAgent::CXFormsDebugAgent()
{
}

CXFormsDebugAgent::~CXFormsDebugAgent()
{
}

STDMETHODIMP CXFormsDebugAgent::getForms(IXMLDOMDocument **ppFormsDOM)
{
	HRESULT hr = E_FAIL;
	try {
		hr = theApp.FormsManager().getFormsDOM(ppFormsDOM);
	}
	catch(std::bad_alloc) {
		if(SUCCEEDED(theApp.FormsManager().RegisterEventLog()))
			theApp.FormsManager().WriteEvent(EVENTLOG_ERROR_TYPE, MSG_MEMEX);
		ASSERT(0);
	}
	catch(...) {
		if(SUCCEEDED(theApp.FormsManager().RegisterEventLog()))
			theApp.FormsManager().WriteEvent(EVENTLOG_ERROR_TYPE, MSG_TOPEX);
		ASSERT(0);
	}
	return hr;
}

STDMETHODIMP CXFormsDebugAgent::getModel(BSTR sFormId, BSTR  sModelId, IXFormsModelElement **ppModel)
{
	HRESULT hr = E_FAIL;
	try {
		hr = theApp.FormsManager().getModel(sFormId, sModelId, ppModel);
	}
	catch(std::bad_alloc) {
		if(SUCCEEDED(theApp.FormsManager().RegisterEventLog()))
			theApp.FormsManager().WriteEvent(EVENTLOG_ERROR_TYPE, MSG_MEMEX);
		ASSERT(0);
	}
	catch(...) {
		if(SUCCEEDED(theApp.FormsManager().RegisterEventLog()))
			theApp.FormsManager().WriteEvent(EVENTLOG_ERROR_TYPE, MSG_TOPEX);
		ASSERT(0);
	}
	return hr;
}

STDMETHODIMP CXFormsDebugAgent::getControls(BSTR sFormId, IXMLDOMDocument **ppControlsDOM)
{
	HRESULT hr = E_FAIL;
	try {
		hr = theApp.FormsManager().getControlsDOM(sFormId, ppControlsDOM);
	}
	catch(std::bad_alloc) {
		if(SUCCEEDED(theApp.FormsManager().RegisterEventLog()))
			theApp.FormsManager().WriteEvent(EVENTLOG_ERROR_TYPE, MSG_MEMEX);
		ASSERT(0);
	}
	catch(...) {
		if(SUCCEEDED(theApp.FormsManager().RegisterEventLog()))
			theApp.FormsManager().WriteEvent(EVENTLOG_ERROR_TYPE, MSG_TOPEX);
		ASSERT(0);
	}
	return hr;
}

STDMETHODIMP CXFormsDebugAgent::getControlInformation(BSTR sFormId, BSTR sControlId, IXMLDOMDocument **ppControlInformationDOM)
{
	HRESULT hr = E_FAIL;
	try {
		hr = theApp.FormsManager().getControlInformationDOM(sFormId, sControlId, ppControlInformationDOM);
	}
	catch(std::bad_alloc) {
		if(SUCCEEDED(theApp.FormsManager().RegisterEventLog()))
			theApp.FormsManager().WriteEvent(EVENTLOG_ERROR_TYPE, MSG_MEMEX);
		ASSERT(0);
	}
	catch(...) {
		if(SUCCEEDED(theApp.FormsManager().RegisterEventLog()))
			theApp.FormsManager().WriteEvent(EVENTLOG_ERROR_TYPE, MSG_TOPEX);
		ASSERT(0);
	}
	return hr;
}

STDMETHODIMP CXFormsDebugAgent::getFormsWithOmnipresentIds(IXMLDOMDocument **ppFormsDOM)
{
	HRESULT hr = E_FAIL;
	try {
		hr = theApp.FormsManager().getFormsDOM(ppFormsDOM, true);
	}
	catch(std::bad_alloc) {
		if(SUCCEEDED(theApp.FormsManager().RegisterEventLog()))
			theApp.FormsManager().WriteEvent(EVENTLOG_ERROR_TYPE, MSG_MEMEX);
		ASSERT(0);
	}
	catch(...) {
		if(SUCCEEDED(theApp.FormsManager().RegisterEventLog()))
			theApp.FormsManager().WriteEvent(EVENTLOG_ERROR_TYPE, MSG_TOPEX);
		ASSERT(0);
	}
	return hr;
}

STDMETHODIMP CXFormsDebugAgent::getModelUsingOmnipresentIds(BSTR sFormId, BSTR  sModelId, IXFormsModelElement **ppModel)
{
	HRESULT hr = E_FAIL;
	try {
		hr = theApp.FormsManager().getModel(sFormId, sModelId, ppModel, true);
	}
	catch(std::bad_alloc) {
		if(SUCCEEDED(theApp.FormsManager().RegisterEventLog()))
			theApp.FormsManager().WriteEvent(EVENTLOG_ERROR_TYPE, MSG_MEMEX);
		ASSERT(0);
	}
	catch(...) {
		if(SUCCEEDED(theApp.FormsManager().RegisterEventLog()))
			theApp.FormsManager().WriteEvent(EVENTLOG_ERROR_TYPE, MSG_TOPEX);
		ASSERT(0);
	}
	return hr;
}

STDMETHODIMP CXFormsDebugAgent::getControlsWithOmnipresentIds(BSTR sFormId, IXMLDOMDocument **ppControlsDOM)
{
	HRESULT hr = E_FAIL;
	try {
		hr = theApp.FormsManager().getControlsDOM(sFormId, ppControlsDOM, true);
	}
	catch(std::bad_alloc) {
		if(SUCCEEDED(theApp.FormsManager().RegisterEventLog()))
			theApp.FormsManager().WriteEvent(EVENTLOG_ERROR_TYPE, MSG_MEMEX);
		ASSERT(0);
	}
	catch(...) {
		if(SUCCEEDED(theApp.FormsManager().RegisterEventLog()))
			theApp.FormsManager().WriteEvent(EVENTLOG_ERROR_TYPE, MSG_TOPEX);
		ASSERT(0);
	}
	return hr;
}

STDMETHODIMP CXFormsDebugAgent::getControlInformationUsingOmnipresentIds(BSTR sFormId, BSTR sControlId, IXMLDOMDocument **ppControlInformationDOM)
{
	HRESULT hr = E_FAIL;
	try {
		hr = theApp.FormsManager().getControlInformationDOM(sFormId, sControlId, ppControlInformationDOM, true);
	}
	catch(std::bad_alloc) {
		if(SUCCEEDED(theApp.FormsManager().RegisterEventLog()))
			theApp.FormsManager().WriteEvent(EVENTLOG_ERROR_TYPE, MSG_MEMEX);
		ASSERT(0);
	}
	catch(...) {
		if(SUCCEEDED(theApp.FormsManager().RegisterEventLog()))
			theApp.FormsManager().WriteEvent(EVENTLOG_ERROR_TYPE, MSG_TOPEX);
		ASSERT(0);
	}
	return hr;
}

STDMETHODIMP CXFormsDebugAgent::getSourceIdFromOmnipresentId(BSTR sId, BSTR *psSourceId)
{
	HRESULT hr = E_FAIL;
	try {
		if(sId && psSourceId) {
			unsigned long ul = wcstoul(sId, 0, 16);
			CImpl *p = reinterpret_cast<CImpl*>(ul - 1 ^ MASK_32_BITS_SET);
			CComBSTR s = p->m_sId;
			*psSourceId = s.Detach();
			if(s.Length() > 0 && s != g_lpwszAnonymous)
				hr = S_OK;
			else
				hr = S_FALSE;
		}
	}
	catch(std::bad_alloc) {
		if(SUCCEEDED(theApp.FormsManager().RegisterEventLog()))
			theApp.FormsManager().WriteEvent(EVENTLOG_ERROR_TYPE, MSG_MEMEX);
		ASSERT(0);
	}
	catch(...) {
		hr = FP_E_BADID;
		SetupErrorInfo(hr, sId);
	}
	return hr;
}

STDMETHODIMP CXFormsDebugAgent::getInstanceDocument(BSTR sId, IXMLDOMDocument **ppDoc)
{
	HRESULT hr = S_OK;
	if(sId && ppDoc) {
		CImplInstance *pInstance = 0;
		hr = FindInstance(sId, true, &pInstance);
		if(hr == S_OK) {
			CDOM3Document * pDomLive = pInstance->GetLiveDOM();
			if(pDomLive)
			{
				*ppDoc = pDomLive->m_pXMLParser;
				(*ppDoc)->AddRef();
			}
		} else if(hr == S_FALSE) {
			hr = FP_E_NOINST;
			SetupErrorInfo(hr, sId);
		}
	} else {
		hr = FP_E_BADARG;
		SetupErrorInfo(hr, L"CXFormsDebugAgent::getInstanceDocument");
	}
	return hr;
}

STDMETHODIMP CXFormsDebugAgent::putInstanceDocument(BSTR sId, IXMLDOMDocument *pDoc)
{
	HRESULT hr = S_OK;
	if(sId && pDoc) {
		CImplInstance *pInstance = 0;
		hr = FindInstance(sId, true, &pInstance);
		if(hr == S_OK)
			hr = pInstance->putInstanceDocument(pDoc);
		else if(hr == S_FALSE) {
			hr = FP_E_NOINST;
			SetupErrorInfo(hr, sId);
		}
	} else {
		hr = FP_E_BADARG;
		SetupErrorInfo(hr, L"CXFormsDebugAgent::putInstanceDocument");
	}
	return hr;
}

STDMETHODIMP CXFormsDebugAgent::getInstanceDocumentWithLiteralId(BSTR sId, IXMLDOMDocument **ppDoc)
{
	HRESULT hr = S_OK;
	if(sId && ppDoc) {
		CImplInstance *pInstance = 0;
		hr = FindInstance(sId, false, &pInstance);
		if(hr == S_OK) {
			CDOM3Document * pDomLive = pInstance->GetLiveDOM();
			if(pDomLive)
			{
				*ppDoc = pDomLive->m_pXMLParser;
				(*ppDoc)->AddRef();
			}
		} else if(hr == S_FALSE) {
			hr = FP_E_NOINST;
			SetupErrorInfo(hr, sId);
		}
	} else {
		hr = FP_E_BADARG;
		SetupErrorInfo(hr, L"CXFormsDebugAgent::getInstanceDocumentWithLiteralId");
	}
	return hr;
}

STDMETHODIMP CXFormsDebugAgent::putInstanceDocumentWithLiteralId(BSTR sId, IXMLDOMDocument *pDoc)
{
	HRESULT hr = S_OK;
	if(sId && pDoc) {
		CImplInstance *pInstance = 0;
		hr = FindInstance(sId, false, &pInstance);
		if(hr == S_OK)
			hr = pInstance->putInstanceDocument(pDoc);
		else if(hr == S_FALSE) {
			hr = FP_E_NOINST;
			SetupErrorInfo(hr, sId);
		}
	} else {
		hr = FP_E_BADARG;
		SetupErrorInfo(hr, L"CXFormsDebugAgent::putInstanceDocumentWithLiteralId");
	}
	return hr;
}

// Search for an instance with a unique id that matches sId. This method is slow.
HRESULT CXFormsDebugAgent::FindInstance(BSTR sId, bool bUseOmnipresentIds, CImplInstance **ppInstance) const
{
	HRESULT hr = S_FALSE;
	if(ppInstance) {
		// Iterate through each form
		CXFormsXFormsElement *pForm = theApp.FormsManager().GetForms(true);
		while(pForm && hr == S_FALSE) {
			CMapStringToPtr *pModels = pForm->getModelList();
			if(pModels) {
				// Iterate through each model on a form
				POSITION pos = pModels->GetStartPosition();
				while(pos && hr == S_FALSE) {
					CString sKey;
					CImplModel *pModel = 0;
					pModels->GetNextAssoc(pos, sKey, reinterpret_cast<void*&>(pModel));
					if(pModel) {
						CMapBSTRToInstancePtr * pInstances = pModel->getInstanceList();
						if(pInstances) {
							CMapBSTRToInstancePtr::iterator i = pInstances->begin();
							while(i != pInstances->end())
							{
								CImplInstance *pInstance = i->second;
								++i;
								if(pInstance) {
									if(bUseOmnipresentIds) {
										CComBSTR s;
										s.Attach(pInstance->UniqueId());
										// Is this the instance we are looking for?
										if(s == sId) {
											hr = S_OK;
											*ppInstance = pInstance;
										}
										s.Empty();
									} else {
										// Is this the instance we are looking for?
										if(pInstance->m_sId == sId) {
											hr = S_OK;
											*ppInstance = pInstance;
											break;
										}
									}
								}
							}
						}
					}
				}
			}
			if(hr == S_FALSE)
				pForm = theApp.FormsManager().GetForms();
		}
	} else {
		hr = FP_E_BADARG;
		SetupErrorInfo(hr, L"CXFormsDebugAgent::FindInstance");
	}
	return hr;
}